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