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