LocationManagerService.java revision 8dbb63419bef8678cf92ebae1d43f549f50987c7
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 String checkPermissionAndRequest(LocationRequest request) { 920 String perm = checkPermission(); 921 922 if (ACCESS_COARSE_LOCATION.equals(perm)) { 923 switch (request.getQuality()) { 924 case LocationRequest.ACCURACY_FINE: 925 request.setQuality(LocationRequest.ACCURACY_BLOCK); 926 break; 927 case LocationRequest.POWER_HIGH: 928 request.setQuality(LocationRequest.POWER_LOW); 929 break; 930 } 931 // throttle 932 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 933 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); 934 } 935 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 936 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); 937 } 938 } 939 // make getFastestInterval() the minimum of interval and fastest interval 940 if (request.getFastestInterval() > request.getInterval()) { 941 request.setFastestInterval(request.getInterval()); 942 } 943 return perm; 944 } 945 946 private void checkPackageName(String packageName) { 947 if (packageName == null) { 948 throw new SecurityException("invalid package name: " + packageName); 949 } 950 int uid = Binder.getCallingUid(); 951 String[] packages = mPackageManager.getPackagesForUid(uid); 952 if (packages == null) { 953 throw new SecurityException("invalid UID " + uid); 954 } 955 for (String pkg : packages) { 956 if (packageName.equals(pkg)) return; 957 } 958 throw new SecurityException("invalid package name: " + packageName); 959 } 960 961 private void checkPendingIntent(PendingIntent intent) { 962 if (intent == null) { 963 throw new IllegalArgumentException("invalid pending intent: " + intent); 964 } 965 } 966 967 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent, 968 int pid, int uid, String packageName) { 969 if (intent == null && listener == null) { 970 throw new IllegalArgumentException("need eiter listener or intent"); 971 } else if (intent != null && listener != null) { 972 throw new IllegalArgumentException("cannot register both listener and intent"); 973 } else if (intent != null) { 974 checkPendingIntent(intent); 975 return getReceiver(intent, pid, uid, packageName); 976 } else { 977 return getReceiver(listener, pid, uid, packageName); 978 } 979 } 980 981 @Override 982 public void requestLocationUpdates(LocationRequest request, ILocationListener listener, 983 PendingIntent intent, String packageName) { 984 if (request == null) request = DEFAULT_LOCATION_REQUEST; 985 checkPackageName(packageName); 986 checkPermissionAndRequest(request); 987 988 final int pid = Binder.getCallingPid(); 989 final int uid = Binder.getCallingUid(); 990 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName); 991 992 // providers may use public location API's, need to clear identity 993 long identity = Binder.clearCallingIdentity(); 994 try { 995 synchronized (mLock) { 996 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName); 997 } 998 } finally { 999 Binder.restoreCallingIdentity(identity); 1000 } 1001 } 1002 1003 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, 1004 int pid, int uid, String packageName) { 1005 // Figure out the provider. Either its explicitly request (legacy use cases), or 1006 // use the fused provider 1007 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1008 String name = request.getProvider(); 1009 if (name == null) name = LocationManager.FUSED_PROVIDER; 1010 LocationProviderInterface provider = mProvidersByName.get(name); 1011 if (provider == null) { 1012 throw new IllegalArgumentException("provider doesn't exisit: " + provider); 1013 } 1014 1015 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " + 1016 name + " " + request + " from " + packageName + "(" + uid + ")"); 1017 1018 UpdateRecord record = new UpdateRecord(name, request, receiver); 1019 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record); 1020 if (oldRecord != null) { 1021 oldRecord.disposeLocked(false); 1022 } 1023 1024 boolean isProviderEnabled = isAllowedBySettingsLocked(name); 1025 if (isProviderEnabled) { 1026 applyRequirementsLocked(name); 1027 } else { 1028 // Notify the listener that updates are currently disabled 1029 receiver.callProviderEnabledLocked(name, false); 1030 } 1031 } 1032 1033 @Override 1034 public void removeUpdates(ILocationListener listener, PendingIntent intent, 1035 String packageName) { 1036 checkPackageName(packageName); 1037 checkPermission(); 1038 final int pid = Binder.getCallingPid(); 1039 final int uid = Binder.getCallingUid(); 1040 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); 1041 1042 // providers may use public location API's, need to clear identity 1043 long identity = Binder.clearCallingIdentity(); 1044 try { 1045 synchronized (mLock) { 1046 removeUpdatesLocked(receiver); 1047 } 1048 } finally { 1049 Binder.restoreCallingIdentity(identity); 1050 } 1051 } 1052 1053 private void removeUpdatesLocked(Receiver receiver) { 1054 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); 1055 1056 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1057 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1058 synchronized (receiver) { 1059 if (receiver.mPendingBroadcasts > 0) { 1060 decrementPendingBroadcasts(); 1061 receiver.mPendingBroadcasts = 0; 1062 } 1063 } 1064 } 1065 1066 // Record which providers were associated with this listener 1067 HashSet<String> providers = new HashSet<String>(); 1068 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords; 1069 if (oldRecords != null) { 1070 // Call dispose() on the obsolete update records. 1071 for (UpdateRecord record : oldRecords.values()) { 1072 record.disposeLocked(false); 1073 } 1074 // Accumulate providers 1075 providers.addAll(oldRecords.keySet()); 1076 } 1077 1078 // update provider 1079 for (String provider : providers) { 1080 // If provider is already disabled, don't need to do anything 1081 if (!isAllowedBySettingsLocked(provider)) { 1082 continue; 1083 } 1084 1085 applyRequirementsLocked(provider); 1086 } 1087 } 1088 1089 @Override 1090 public Location getLastLocation(LocationRequest request, String packageName) { 1091 if (D) Log.d(TAG, "getLastLocation: " + request); 1092 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1093 String perm = checkPermissionAndRequest(request); 1094 checkPackageName(packageName); 1095 1096 if (mBlacklist.isBlacklisted(packageName)) { 1097 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + 1098 packageName); 1099 return null; 1100 } 1101 1102 synchronized (mLock) { 1103 // Figure out the provider. Either its explicitly request (deprecated API's), 1104 // or use the fused provider 1105 String name = request.getProvider(); 1106 if (name == null) name = LocationManager.FUSED_PROVIDER; 1107 LocationProviderInterface provider = mProvidersByName.get(name); 1108 if (provider == null) return null; 1109 1110 if (!isAllowedBySettingsLocked(name)) return null; 1111 1112 Location location = mLastLocation.get(name); 1113 if (ACCESS_FINE_LOCATION.equals(perm)) { 1114 return location; 1115 } else { 1116 return mLocationFudger.getOrCreate(location); 1117 } 1118 } 1119 } 1120 1121 @Override 1122 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, 1123 String packageName) { 1124 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1125 checkGeofencePermission(); 1126 checkPermissionAndRequest(request); 1127 checkPendingIntent(intent); 1128 checkPackageName(packageName); 1129 1130 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent); 1131 1132 // geo-fence manager uses the public location API, need to clear identity 1133 int uid = Binder.getCallingUid(); 1134 long identity = Binder.clearCallingIdentity(); 1135 try { 1136 mGeofenceManager.addFence(request, geofence, intent, uid, packageName); 1137 } finally { 1138 Binder.restoreCallingIdentity(identity); 1139 } 1140 } 1141 1142 @Override 1143 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1144 checkGeofencePermission(); 1145 checkPendingIntent(intent); 1146 checkPackageName(packageName); 1147 1148 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1149 1150 // geo-fence manager uses the public location API, need to clear identity 1151 long identity = Binder.clearCallingIdentity(); 1152 try { 1153 mGeofenceManager.removeFence(geofence, intent); 1154 } finally { 1155 Binder.restoreCallingIdentity(identity); 1156 } 1157 } 1158 1159 1160 @Override 1161 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1162 if (mGpsStatusProvider == null) { 1163 return false; 1164 } 1165 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1166 PackageManager.PERMISSION_GRANTED) { 1167 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1168 } 1169 1170 try { 1171 mGpsStatusProvider.addGpsStatusListener(listener); 1172 } catch (RemoteException e) { 1173 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1174 return false; 1175 } 1176 return true; 1177 } 1178 1179 @Override 1180 public void removeGpsStatusListener(IGpsStatusListener listener) { 1181 synchronized (mLock) { 1182 try { 1183 mGpsStatusProvider.removeGpsStatusListener(listener); 1184 } catch (Exception e) { 1185 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1186 } 1187 } 1188 } 1189 1190 @Override 1191 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1192 if (provider == null) { 1193 // throw NullPointerException to remain compatible with previous implementation 1194 throw new NullPointerException(); 1195 } 1196 1197 checkPermission(); 1198 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1199 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1200 != PackageManager.PERMISSION_GRANTED)) { 1201 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1202 } 1203 1204 synchronized (mLock) { 1205 LocationProviderInterface p = mProvidersByName.get(provider); 1206 if (p == null) return false; 1207 1208 return p.sendExtraCommand(command, extras); 1209 } 1210 } 1211 1212 @Override 1213 public boolean sendNiResponse(int notifId, int userResponse) { 1214 if (Binder.getCallingUid() != Process.myUid()) { 1215 throw new SecurityException( 1216 "calling sendNiResponse from outside of the system is not allowed"); 1217 } 1218 try { 1219 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1220 } catch (RemoteException e) { 1221 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1222 return false; 1223 } 1224 } 1225 1226 /** 1227 * @return null if the provider does not exist 1228 * @throws SecurityException if the provider is not allowed to be 1229 * accessed by the caller 1230 */ 1231 @Override 1232 public ProviderProperties getProviderProperties(String provider) { 1233 checkPermission(); 1234 1235 LocationProviderInterface p; 1236 synchronized (mLock) { 1237 p = mProvidersByName.get(provider); 1238 } 1239 1240 if (p == null) return null; 1241 return p.getProperties(); 1242 } 1243 1244 @Override 1245 public boolean isProviderEnabled(String provider) { 1246 checkPermission(); 1247 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1248 1249 synchronized (mLock) { 1250 LocationProviderInterface p = mProvidersByName.get(provider); 1251 if (p == null) return false; 1252 1253 return isAllowedBySettingsLocked(provider); 1254 } 1255 } 1256 1257 private void checkCallerIsProvider() { 1258 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1259 == PackageManager.PERMISSION_GRANTED) { 1260 return; 1261 } 1262 1263 // Previously we only used the INSTALL_LOCATION_PROVIDER 1264 // check. But that is system or signature 1265 // protection level which is not flexible enough for 1266 // providers installed oustide the system image. So 1267 // also allow providers with a UID matching the 1268 // currently bound package name 1269 1270 int uid = Binder.getCallingUid(); 1271 1272 if (mGeocodeProvider != null) { 1273 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return; 1274 } 1275 for (LocationProviderProxy proxy : mProxyProviders) { 1276 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return; 1277 } 1278 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 1279 "or UID of a currently bound location provider"); 1280 } 1281 1282 private boolean doesPackageHaveUid(int uid, String packageName) { 1283 if (packageName == null) { 1284 return false; 1285 } 1286 try { 1287 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0); 1288 if (appInfo.uid != uid) { 1289 return false; 1290 } 1291 } catch (NameNotFoundException e) { 1292 return false; 1293 } 1294 return true; 1295 } 1296 1297 @Override 1298 public void reportLocation(Location location, boolean passive) { 1299 checkCallerIsProvider(); 1300 1301 if (!location.isComplete()) { 1302 Log.w(TAG, "Dropping incomplete location: " + location); 1303 return; 1304 } 1305 1306 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 1307 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 1308 m.arg1 = (passive ? 1 : 0); 1309 mLocationHandler.sendMessageAtFrontOfQueue(m); 1310 } 1311 1312 1313 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1314 // Always broadcast the first update 1315 if (lastLoc == null) { 1316 return true; 1317 } 1318 1319 // Check whether sufficient time has passed 1320 long minTime = record.mRequest.getFastestInterval(); 1321 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L; 1322 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 1323 return false; 1324 } 1325 1326 // Check whether sufficient distance has been traveled 1327 double minDistance = record.mRequest.getSmallestDisplacement(); 1328 if (minDistance > 0.0) { 1329 if (loc.distanceTo(lastLoc) <= minDistance) { 1330 return false; 1331 } 1332 } 1333 1334 return true; 1335 } 1336 1337 private void handleLocationChangedLocked(Location location, boolean passive) { 1338 if (D) Log.d(TAG, "incoming location: " + location); 1339 1340 long now = SystemClock.elapsedRealtime(); 1341 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1342 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1343 if (records == null || records.size() == 0) return; 1344 1345 LocationProviderInterface p = mProvidersByName.get(provider); 1346 if (p == null) return; 1347 1348 // Add the coarse location as an extra 1349 Location coarse = mLocationFudger.getOrCreate(location); 1350 1351 // Update last known locations 1352 Location lastLocation = mLastLocation.get(provider); 1353 if (lastLocation == null) { 1354 lastLocation = new Location(provider); 1355 mLastLocation.put(provider, lastLocation); 1356 } 1357 lastLocation.set(location); 1358 1359 // Fetch latest status update time 1360 long newStatusUpdateTime = p.getStatusUpdateTime(); 1361 1362 // Get latest status 1363 Bundle extras = new Bundle(); 1364 int status = p.getStatus(extras); 1365 1366 ArrayList<Receiver> deadReceivers = null; 1367 ArrayList<UpdateRecord> deadUpdateRecords = null; 1368 1369 // Broadcast location or status to all listeners 1370 for (UpdateRecord r : records) { 1371 Receiver receiver = r.mReceiver; 1372 boolean receiverDead = false; 1373 1374 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 1375 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 1376 receiver.mPackageName); 1377 continue; 1378 } 1379 1380 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { 1381 location = lastLocation; // use fine location 1382 } else { 1383 location = coarse; // use coarse location 1384 } 1385 1386 Location lastLoc = r.mLastFixBroadcast; 1387 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1388 if (lastLoc == null) { 1389 lastLoc = new Location(location); 1390 r.mLastFixBroadcast = lastLoc; 1391 } else { 1392 lastLoc.set(location); 1393 } 1394 if (!receiver.callLocationChangedLocked(location)) { 1395 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1396 receiverDead = true; 1397 } 1398 } 1399 1400 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1401 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1402 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1403 1404 r.mLastStatusBroadcast = newStatusUpdateTime; 1405 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1406 receiverDead = true; 1407 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1408 } 1409 } 1410 1411 // track expired records 1412 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) { 1413 if (deadUpdateRecords == null) { 1414 deadUpdateRecords = new ArrayList<UpdateRecord>(); 1415 } 1416 deadUpdateRecords.add(r); 1417 } 1418 // track dead receivers 1419 if (receiverDead) { 1420 if (deadReceivers == null) { 1421 deadReceivers = new ArrayList<Receiver>(); 1422 } 1423 if (!deadReceivers.contains(receiver)) { 1424 deadReceivers.add(receiver); 1425 } 1426 } 1427 } 1428 1429 // remove dead records and receivers outside the loop 1430 if (deadReceivers != null) { 1431 for (Receiver receiver : deadReceivers) { 1432 removeUpdatesLocked(receiver); 1433 } 1434 } 1435 if (deadUpdateRecords != null) { 1436 for (UpdateRecord r : deadUpdateRecords) { 1437 r.disposeLocked(true); 1438 } 1439 } 1440 } 1441 1442 private class LocationWorkerHandler extends Handler { 1443 @Override 1444 public void handleMessage(Message msg) { 1445 switch (msg.what) { 1446 case MSG_LOCATION_CHANGED: 1447 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 1448 break; 1449 } 1450 } 1451 } 1452 1453 private void handleLocationChanged(Location location, boolean passive) { 1454 String provider = location.getProvider(); 1455 1456 if (!passive) { 1457 // notify passive provider of the new location 1458 mPassiveProvider.updateLocation(location); 1459 } 1460 1461 synchronized (mLock) { 1462 if (isAllowedBySettingsLocked(provider)) { 1463 handleLocationChangedLocked(location, passive); 1464 } 1465 } 1466 } 1467 1468 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1469 @Override 1470 public void onPackageDisappeared(String packageName, int reason) { 1471 // remove all receivers associated with this package name 1472 synchronized (mLock) { 1473 ArrayList<Receiver> deadReceivers = null; 1474 1475 for (Receiver receiver : mReceivers.values()) { 1476 if (receiver.mPackageName.equals(packageName)) { 1477 if (deadReceivers == null) { 1478 deadReceivers = new ArrayList<Receiver>(); 1479 } 1480 deadReceivers.add(receiver); 1481 } 1482 } 1483 1484 // perform removal outside of mReceivers loop 1485 if (deadReceivers != null) { 1486 for (Receiver receiver : deadReceivers) { 1487 removeUpdatesLocked(receiver); 1488 } 1489 } 1490 } 1491 } 1492 }; 1493 1494 // Wake locks 1495 1496 private void incrementPendingBroadcasts() { 1497 synchronized (mWakeLock) { 1498 if (mPendingBroadcasts++ == 0) { 1499 try { 1500 mWakeLock.acquire(); 1501 log("Acquired wakelock"); 1502 } catch (Exception e) { 1503 // This is to catch a runtime exception thrown when we try to release an 1504 // already released lock. 1505 Slog.e(TAG, "exception in acquireWakeLock()", e); 1506 } 1507 } 1508 } 1509 } 1510 1511 private void decrementPendingBroadcasts() { 1512 synchronized (mWakeLock) { 1513 if (--mPendingBroadcasts == 0) { 1514 try { 1515 // Release wake lock 1516 if (mWakeLock.isHeld()) { 1517 mWakeLock.release(); 1518 log("Released wakelock"); 1519 } else { 1520 log("Can't release wakelock again!"); 1521 } 1522 } catch (Exception e) { 1523 // This is to catch a runtime exception thrown when we try to release an 1524 // already released lock. 1525 Slog.e(TAG, "exception in releaseWakeLock()", e); 1526 } 1527 } 1528 } 1529 } 1530 1531 // Geocoder 1532 1533 @Override 1534 public boolean geocoderIsPresent() { 1535 return mGeocodeProvider != null; 1536 } 1537 1538 @Override 1539 public String getFromLocation(double latitude, double longitude, int maxResults, 1540 GeocoderParams params, List<Address> addrs) { 1541 if (mGeocodeProvider != null) { 1542 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1543 params, addrs); 1544 } 1545 return null; 1546 } 1547 1548 1549 @Override 1550 public String getFromLocationName(String locationName, 1551 double lowerLeftLatitude, double lowerLeftLongitude, 1552 double upperRightLatitude, double upperRightLongitude, int maxResults, 1553 GeocoderParams params, List<Address> addrs) { 1554 1555 if (mGeocodeProvider != null) { 1556 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1557 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1558 maxResults, params, addrs); 1559 } 1560 return null; 1561 } 1562 1563 // Mock Providers 1564 1565 private void checkMockPermissionsSafe() { 1566 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1567 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1568 if (!allowMocks) { 1569 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1570 } 1571 1572 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1573 PackageManager.PERMISSION_GRANTED) { 1574 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1575 } 1576 } 1577 1578 @Override 1579 public void addTestProvider(String name, ProviderProperties properties) { 1580 checkMockPermissionsSafe(); 1581 1582 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 1583 throw new IllegalArgumentException("Cannot mock the passive location provider"); 1584 } 1585 1586 long identity = Binder.clearCallingIdentity(); 1587 synchronized (mLock) { 1588 MockProvider provider = new MockProvider(name, this, properties); 1589 // remove the real provider if we are replacing GPS or network provider 1590 if (LocationManager.GPS_PROVIDER.equals(name) 1591 || LocationManager.NETWORK_PROVIDER.equals(name) 1592 || LocationManager.FUSED_PROVIDER.equals(name)) { 1593 LocationProviderInterface p = mProvidersByName.get(name); 1594 if (p != null) { 1595 removeProviderLocked(p); 1596 } 1597 } 1598 if (mProvidersByName.get(name) != null) { 1599 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1600 } 1601 addProviderLocked(provider); 1602 mMockProviders.put(name, provider); 1603 mLastLocation.put(name, null); 1604 updateProvidersLocked(); 1605 } 1606 Binder.restoreCallingIdentity(identity); 1607 } 1608 1609 @Override 1610 public void removeTestProvider(String provider) { 1611 checkMockPermissionsSafe(); 1612 synchronized (mLock) { 1613 MockProvider mockProvider = mMockProviders.get(provider); 1614 if (mockProvider == null) { 1615 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1616 } 1617 long identity = Binder.clearCallingIdentity(); 1618 removeProviderLocked(mProvidersByName.get(provider)); 1619 mMockProviders.remove(mockProvider); 1620 1621 // reinstate real provider if available 1622 LocationProviderInterface realProvider = mRealProviders.get(provider); 1623 if (realProvider != null) { 1624 addProviderLocked(realProvider); 1625 } 1626 mLastLocation.put(provider, null); 1627 updateProvidersLocked(); 1628 Binder.restoreCallingIdentity(identity); 1629 } 1630 } 1631 1632 @Override 1633 public void setTestProviderLocation(String provider, Location loc) { 1634 checkMockPermissionsSafe(); 1635 synchronized (mLock) { 1636 MockProvider mockProvider = mMockProviders.get(provider); 1637 if (mockProvider == null) { 1638 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1639 } 1640 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 1641 long identity = Binder.clearCallingIdentity(); 1642 mockProvider.setLocation(loc); 1643 Binder.restoreCallingIdentity(identity); 1644 } 1645 } 1646 1647 @Override 1648 public void clearTestProviderLocation(String provider) { 1649 checkMockPermissionsSafe(); 1650 synchronized (mLock) { 1651 MockProvider mockProvider = mMockProviders.get(provider); 1652 if (mockProvider == null) { 1653 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1654 } 1655 mockProvider.clearLocation(); 1656 } 1657 } 1658 1659 @Override 1660 public void setTestProviderEnabled(String provider, boolean enabled) { 1661 checkMockPermissionsSafe(); 1662 synchronized (mLock) { 1663 MockProvider mockProvider = mMockProviders.get(provider); 1664 if (mockProvider == null) { 1665 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1666 } 1667 long identity = Binder.clearCallingIdentity(); 1668 if (enabled) { 1669 mockProvider.enable(); 1670 mEnabledProviders.add(provider); 1671 mDisabledProviders.remove(provider); 1672 } else { 1673 mockProvider.disable(); 1674 mEnabledProviders.remove(provider); 1675 mDisabledProviders.add(provider); 1676 } 1677 updateProvidersLocked(); 1678 Binder.restoreCallingIdentity(identity); 1679 } 1680 } 1681 1682 @Override 1683 public void clearTestProviderEnabled(String provider) { 1684 checkMockPermissionsSafe(); 1685 synchronized (mLock) { 1686 MockProvider mockProvider = mMockProviders.get(provider); 1687 if (mockProvider == null) { 1688 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1689 } 1690 long identity = Binder.clearCallingIdentity(); 1691 mEnabledProviders.remove(provider); 1692 mDisabledProviders.remove(provider); 1693 updateProvidersLocked(); 1694 Binder.restoreCallingIdentity(identity); 1695 } 1696 } 1697 1698 @Override 1699 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1700 checkMockPermissionsSafe(); 1701 synchronized (mLock) { 1702 MockProvider mockProvider = mMockProviders.get(provider); 1703 if (mockProvider == null) { 1704 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1705 } 1706 mockProvider.setStatus(status, extras, updateTime); 1707 } 1708 } 1709 1710 @Override 1711 public void clearTestProviderStatus(String provider) { 1712 checkMockPermissionsSafe(); 1713 synchronized (mLock) { 1714 MockProvider mockProvider = mMockProviders.get(provider); 1715 if (mockProvider == null) { 1716 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1717 } 1718 mockProvider.clearStatus(); 1719 } 1720 } 1721 1722 private void log(String log) { 1723 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1724 Slog.d(TAG, log); 1725 } 1726 } 1727 1728 @Override 1729 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1730 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1731 != PackageManager.PERMISSION_GRANTED) { 1732 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 1733 + Binder.getCallingPid() 1734 + ", uid=" + Binder.getCallingUid()); 1735 return; 1736 } 1737 1738 synchronized (mLock) { 1739 pw.println("Current Location Manager state:"); 1740 pw.println(" Location Listeners:"); 1741 for (Receiver receiver : mReceivers.values()) { 1742 pw.println(" " + receiver); 1743 } 1744 pw.println(" Records by Provider:"); 1745 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 1746 pw.println(" " + entry.getKey() + ":"); 1747 for (UpdateRecord record : entry.getValue()) { 1748 pw.println(" " + record); 1749 } 1750 } 1751 pw.println(" Last Known Locations:"); 1752 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 1753 String provider = entry.getKey(); 1754 Location location = entry.getValue(); 1755 pw.println(" " + provider + ": " + location); 1756 } 1757 1758 mGeofenceManager.dump(pw); 1759 1760 if (mEnabledProviders.size() > 0) { 1761 pw.println(" Enabled Providers:"); 1762 for (String i : mEnabledProviders) { 1763 pw.println(" " + i); 1764 } 1765 1766 } 1767 if (mDisabledProviders.size() > 0) { 1768 pw.println(" Disabled Providers:"); 1769 for (String i : mDisabledProviders) { 1770 pw.println(" " + i); 1771 } 1772 } 1773 pw.append(" "); 1774 mBlacklist.dump(pw); 1775 if (mMockProviders.size() > 0) { 1776 pw.println(" Mock Providers:"); 1777 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 1778 i.getValue().dump(pw, " "); 1779 } 1780 } 1781 1782 pw.append(" fudger: "); 1783 mLocationFudger.dump(fd, pw, args); 1784 1785 if (args.length > 0 && "short".equals(args[0])) { 1786 return; 1787 } 1788 for (LocationProviderInterface provider: mProviders) { 1789 pw.print(provider.getName() + " Internal State"); 1790 if (provider instanceof LocationProviderProxy) { 1791 LocationProviderProxy proxy = (LocationProviderProxy) provider; 1792 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 1793 } 1794 pw.println(":"); 1795 provider.dump(fd, pw, args); 1796 } 1797 } 1798 } 1799} 1800