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