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